﻿#include "socketfd_port.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/utime.h>

int set_recv_timeout(SOCKETFD sockfd, int ms)
{
    // WINDOWS
    DWORD timeout = ms;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
    return 0;
}

int connect_timeout(SOCKETFD connectSOCK, struct sockaddr_in* addrsrv, int timeoutms)
{
    // put socked in non-blocking mode...
    u_long block = 1;
    if (ioctlsocket(connectSOCK, FIONBIO, &block) == SOCKET_ERROR) {
        return -1;
    }

    if (connect(connectSOCK, (struct sockaddr*)addrsrv, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
        int sta = WSAGetLastError();
        if (sta != WSAEWOULDBLOCK) {
            // connection failed
            return -2;
        }

        // connection pending

        fd_set setW, setE;

        FD_ZERO(&setW);
        FD_SET(connectSOCK, &setW);
        FD_ZERO(&setE);
        FD_SET(connectSOCK, &setE);

        struct timeval time_out = {
            .tv_sec  = 0,
            .tv_usec = timeoutms * 1000,
        };

        int ret = select(0, NULL, &setW, &setE, &time_out);
        if (ret <= 0) {
            // select() failed or connection timed out
            if (ret == 0)
                WSASetLastError(WSAETIMEDOUT);
            return -3;
        }

        if (FD_ISSET(connectSOCK, &setE)) {
            // connection failed
            int err = 0;
            int len = sizeof(err);
            err     = getsockopt(connectSOCK, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
            WSASetLastError(err);
            return -4;
        }
    }

    // connection successful

    // put socked in blocking mode...
    block = 0;
    if (ioctlsocket(connectSOCK, FIONBIO, &block) == SOCKET_ERROR) {
        return -5;
    }
    return 0;
}
